#ifndef __P_QUEUE_H__
#define __P_QUEUE_H__

#include <queue>
#include <list>
#include <zlib/lib/Ink_time.h>
#include <zlib/lib/Ink_pthread.h>
#include "I_Event.h"

struct BlockNotifyQueue {
	void enqueue(Event *e, bool fast_signal = false);
	void signal();
	bool try_signal();
	void enqueue_local_all();
	void enqueue_local(Event *e);
	Event *dequeue_local();
	void dequeue_time(ink_hrtime cur_htime, ink_hrtime timeout, bool sleep);

	std::queue<Event *> g_que;
	std::queue<Event *> local_que;

	ink_mutex lock;
	ink_cond might_have_data;

	BlockNotifyQueue();
};

extern void flush_signal(EThread *thr);

template <typename T>
struct BlockQueue
{
	BlockQueue();
	void enqueue(T t);
	void remove(T t);
	T dequeue();

	std::list<T> b_que;
	ink_mutex lock;
};

template <typename T>
BlockQueue<T>::BlockQueue()
{
	ink_mutex_init(&lock);
}

template <typename T> void
BlockQueue<T>::enqueue(T t)
{
	ink_mutex_lock(&lock);
	b_que.push_back(t);
	ink_mutex_release(&lock);
}

template <typename T> void
BlockQueue<T>::remove(T t)
{
	ink_mutex_lock(&lock);
	typename std::list<T>::iterator it;
	for(it = b_que.begin(); it != b_que.end(); it++)
	{
		if(t == *it)
		{
			b_que.erase(it);
			break;
		}
	}
	ink_mutex_release(&lock);
}

template <typename T> T
BlockQueue<T>::dequeue()
{
	T t = NULL;
	ink_mutex_lock(&lock);
	if(!b_que.empty())
	{
		t = b_que.front();
		b_que.pop_front();
	}
	ink_mutex_release(&lock);

	return t;
}

struct PriorityEvent {
	ink_hrtime exec_time;
	Event *e;

	bool operator < (const PriorityEvent &e)
	{
		return exec_time < e.exec_time;
	}

	PriorityEvent() : exec_time(0), e(NULL)
	{}
};

struct PriorityQueue {

	PriorityQueue(){}

	void enqueue(Event *e, ink_hrtime time);
	void check_ready(ink_hrtime time);
	ink_hrtime get_near_exec_time();
	Event *dequeue();

	std::list<PriorityEvent> prior_list;
	std::list<PriorityEvent> exec_list;
};

struct NegativeQueue {
	NegativeQueue(){}

	void enqueue(Event *e);
	Event *dequeue();
	bool empty();

	std::list<Event *> neg_list;
};

template <typename T>
struct NonBlockList
{
	NonBlockList();
	void enqueue(T t);
	void remove(T t);
	T dequeue();

	bool empty();

	std::list<T> nb_list;
};

template <typename T> bool
NonBlockList<T>::empty()
{
	return nb_list.empty();
}

template <typename T>
NonBlockList<T>::NonBlockList()
{
}

template <typename T> void
NonBlockList<T>::enqueue(T t)
{
	nb_list.push_back(t);
}

template <typename T> void
NonBlockList<T>::remove(T t)
{
	typename std::list<T>::iterator it;
	for(it = nb_list.begin(); it != nb_list.end(); it++)
	{
		if(t == *it)
		{
			nb_list.erase(it);
			break;
		}
	}
}

template <typename T> T
NonBlockList<T>::dequeue()
{
	T t = NULL;

	if(!nb_list.empty())
	{
		t = nb_list.front();
		nb_list.pop_front();
	}

	return t;
}

#endif //__P_QUEUE_H__
